#include "./app_task.h"
#include "./handler_task.h"
#include "./status_task.h"
#include "../xlib/rcc.h"
#include "../pub_driver/cmd_can.h"
#include "../heat_driver/ctrl.h"
#include "../heat_driver/sensor.h"
#include "../utils/log.h"
#include "../heat_driver/motors.h"
#include "./draw_hot_task.h"
#include "./draw_tank_task.h"
#include "../cfg/heat_info.h"
#include "./heat_task.h"
#include "./steam_task.h"

namespace heat_task {

AppTask appTask;

using namespace pub_driver;
using namespace heat_driver;

static void event_loop();

void AppTask::run() {
    stm32f1::rcc::use_swd();
    cmdCAN.init();
    sensor.init();
    ctrl.init();
    cfg::heatInfo.load();
    motors.init();
    handlerTask.init_start();
    drawHotTask.init_start();
    heatTask.init_start();
    drawTankTask.init_start();
    steamTask.init_start();
    statusTask.start();
    println("heat app run");

    event_loop();
}

using namespace conn;
using namespace cfg;

static void handle_fast_req(const Frame &frame) {

    cmdCAN.ack(frame);
    cmdCAN.ipcReceiver.recv_next(frame.len);
    handlerTask.post(frame);
}

static void handle_query(const Frame &frame) {
    
    switch (frame.seq_cmd()) {
        case proto::pub::QUERY_TASK_INFO: {
            const TaskInfo &taks_info = handlerTask.task_info;
            cmdCAN.result(frame, taks_info.seq,taks_info.cmd);
        }; break;

        case proto::heat::QUERY_DRAW: {
            uint16_t tank_draw_time = heatInfo->tank_draw_time / 60 / 1000;
            uint16_t hot_draw_time = heatInfo->hot_draw_time / 60 / 1000;
            cmdCAN.result(frame, tank_draw_time, hot_draw_time);
        }; break;

        case proto::heat::QUERY_HEAT: {
            uint16_t hot_water_heat_time = heatInfo->hot_water_heat_time / 60 / 1000;
            uint16_t hot_steam_heat_time = heatInfo->hot_steam_heat_time / 60 / 1000;
            uint8_t hot_water_temp = heatInfo->hot_water_temp;
            uint8_t hot_steam_temp = heatInfo->hot_steam_temp;
            cmdCAN.result(
                frame, 
                hot_water_heat_time,
                hot_steam_heat_time,
                hot_water_temp,
                hot_steam_temp
            );
        }; break;

        case proto::heat::QUERY_FLOW: {
            uint16_t flow = heatInfo->flow;
            cmdCAN.result(
                frame,
                flow
            );
        }; break;

        case proto::heat::BEGIN_STEAM: {
            steamTask.begin();
            cmdCAN.result(frame, ec::pub::OK);
        }; break;

        case proto::heat::OPEN_STEAM: {
            uint8_t sec;
            Error err = frame.parse_query(sec);
            if (err) {
                cmdCAN.result(frame, ec::pub::INVALID);
                break;
            }
            steamTask.open( sec );
            cmdCAN.result(frame, ec::pub::OK);
        }; break;

        case proto::heat::CLOSE_STEAM: {
            steamTask.close();
            cmdCAN.result(frame, ec::pub::OK);
        }; break;
    }
}

static void event_loop() {
    Frame frame;

    for (;;) {
        cmdCAN.ipcReceiver.recv_from(frame);
        switch (frame.type()) {
            case type::PING: cmdCAN.pong(frame); break;
            case type::FAST_REQ: handle_fast_req(frame); break;
            case type::QUERY: handle_query(frame); break;
        }
    }
}


}
